#pragma once
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <stdarg.h>

/*
*	字符串
*  支持%s,%S,%d,%b,%x/%X,%q,%[n]z,
*  %s: 正常字符串
*  %d: 正常十进制
*  %x: 正常十六进制
*	%q: 替换sql字符串格式
*  %t: 以YYYY-MM-DD hh:mm:ss格式打印字符串time(NULL)为例
*/
template <size_t TSize = 256>
class url_string
{
public:
    url_string()
	{
		construct();
	}

    url_string(const char* str)
	{
		construct();
		append(str);
	}

    url_string(const url_string& t)
	{
		construct();
		push_back(t.c_str(), t.length());
	}

    virtual ~url_string()
	{
		if(NULL != m_heap_buffer)
		{
			free(m_heap_buffer);
		}
	}
private:
	void construct()
	{
		m_heap_buffer = NULL;
		m_size = sizeof(m_statck_buffer);
		m_pos = 0;
		memset(m_statck_buffer, 0, sizeof(m_statck_buffer));
	}

public:
	void	format(const char* fmt, ...)
	{
		va_list		var;

		clear();	// 初始置空
		va_start(var, fmt);
		format_v(fmt, var);
		va_end(var);
	}

	void	append(const char* fmt, ...)
	{
		va_list		var;

		va_start(var, fmt);
		format_v(fmt, var);
		va_end(var);
	}

	void	format_v(const char* fmt, va_list var)
	{
		for(int iBuf = 0; *fmt; fmt++)
		{
			if('%' == *fmt)
			{
				fmt++;
                if('s' == *fmt || 'u' == *fmt)
				{
					// 直接替换
					char* pdata		= va_arg(var, char*);

					if(NULL == pdata)
					{
						continue;
					}

                    if('s' == *fmt)
					{
						push_back(pdata, strlen(pdata));
					}
					else
					{
						for(; *pdata; pdata++)
						{
                            if('\x20' == *pdata)
							{
                                push_back('+');
							}
                            else if( (*pdata >= 'a' && *pdata <= 'z')
                                     || (*pdata >= 'A' && *pdata <= 'Z')
                                     || (*pdata >= '0' && *pdata <= '9')
                                     || '!' == *pdata
                                     || '(' == *pdata
                                     || ')' == *pdata
                                     || '_' == *pdata
                                     || '-' == *pdata)
                            {
                                push_back(*pdata);
                            }
                            else
                            {
                                // 转义字符
                                char    *tab        = "0123456789abcdef";

                                push_back('%');
                                push_back(tab[ (*pdata >> 4) & 0xf ]);
                                push_back(tab[ (*pdata) & 0xf ]);
                            }
						}
					}
				}
				else if('d' == *fmt || 'x' == *fmt)
				{
					// 替换数字
					int				ndata		= va_arg(var, int);
					char			data[128]	= {0};

					sprintf(data, ('d' == *fmt)?"%d":"%x", ndata);
					push_back(data, strlen(data));
				}
				else if('t' == *fmt)
				{
					// 替换日期 time(NULL)
					time_t			t			= va_arg(var, time_t);
					struct tm		tm			= {0};
					char			date[128]	= {0};

                    localtime_r(&t, &tm);
                    sprintf(date, "%04d-%02d-%02d+%02d%%3a%02d%%3a%02d",
						tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
						tm.tm_hour, tm.tm_min, tm.tm_sec);
					push_back(date, strlen(date));
				}
                else
				{
					push_back('%');
					push_back(*fmt);
				}

				continue;
			}

			push_back(*fmt);
		}
	}

	void	push_back(const char c)
	{
		if(m_pos >= (m_size - 1))
		{
			resize(m_size + TSize * 2);
		}

		char*	p	= (char *)c_str();

		p[m_pos] = c;
		p[m_pos+1] = 0;
		m_pos++;
	}

	void	push_back(const char* str, size_t len)
	{
		if((m_pos + len) >= (m_size - 1))
		{
			resize(m_size + (len + TSize * 2) / TSize * TSize);
		}

		memcpy((char *)c_str() + m_pos, str, len);
		m_pos += len;
		set(m_pos, 0);
	}

	void	resize(size_t size)
	{
		if(m_size < size)
		{
			if(sizeof(m_statck_buffer) < size)
			{
				if(NULL != m_heap_buffer)
				{
					char* buff = (char *)realloc(m_heap_buffer, size);

					if(NULL == buff)
					{
						buff = (char *)malloc(size);
						memcpy(buff, m_heap_buffer, m_size);
						free(m_heap_buffer);
					}

					m_heap_buffer = buff;
					m_size = size;
				}
				else
				{
					m_heap_buffer = (char *)malloc(size);
					memset(m_heap_buffer, 0, size);
					memcpy(m_heap_buffer, m_statck_buffer, m_pos);
					m_size = size;
				}
			}
		}
		// 截断字符串
		if(m_pos > size)
		{
			m_pos = size;
			set(m_pos, 0);
		}
	}

	void clear()
	{
		memset((char *)c_str(), 0, m_pos);
		m_pos = 0;
	}

	const char*	c_str()
	{
		if(NULL != m_heap_buffer)
		{
			return m_heap_buffer;
		}

		return m_statck_buffer;
	}

	size_t length()
	{
		return strlen(c_str());
	}

	size_t size()
	{
		return m_pos;
	}

private:
	void		set(size_t pos, char c)
	{
		((char *)c_str())[pos] = c;
	}

private:
	size_t		m_size;
	size_t		m_pos;
	char		m_statck_buffer[TSize];
	char		*m_heap_buffer;
};
